import socket  # 导入socket模块，用来实现socket通信
import os
from myProtocol import MyProtocol, receive_full_data


class FtpClient(object):

    def __init__(self):
        self.client = socket.socket()  # 声明客户端利用socket通信

    @staticmethod
    def help(self):  # 写一个打印一些指令的帮助信息函数，
        msg = '''
support commends:
    upload filename
    download filename
    show
        '''
        print(msg)

    def connect(self, ip, port):  # 定义一个连接服务器函数，调用client.connect()方法，连接服务器端
        self.client.connect((ip, port))

    def interactive(self):  # 定义一个与服务器交互的函数
        while True:
            cmd = input('>>').strip()  # 用户在客户端输入指令，strip()去掉用户输入指令的空格和换行符
            if len(cmd) == 0:
                continue
            cmd_str = cmd.split()[0]  # 拆分指令的第一个字符赋给cmd_str
            # 反射
            if hasattr(self, 'cmd_%s' % cmd_str):  # hasattr() 函数用于判断对象是否包含对应的属性
                func = getattr(self, 'cmd_%s' % cmd_str)  # 函数用于返回一个对象属性值
                func(cmd)
            else:
                FtpClient.help(self)

    def cmd_upload(self, *args):
        cmd_split = args[0].split()
        if len(cmd_split) > 1:
            filename = cmd_split[1]
            if os.path.isfile(filename):
                # 读取文件内容
                with open(filename, 'rb') as f:
                    file_data = f.read()
                # 创建 MyProtocol 实例
                protocol = MyProtocol(
                    version=2,
                    magic=0x1234,
                    method='upload',
                    filename=filename,
                    data=file_data
                )
                # 编码并发送数据
                encoded_data = protocol.encode()
                print(f'发送：{protocol}')
                self.client.sendall(encoded_data)
                total_data = receive_full_data(self.client, MyProtocol.header_size)
                if total_data:
                    print('-------收到服务端回复-------')
                    receive_data = MyProtocol.decode(total_data)
                    if receive_data == 0:
                        print('请检查协议设置或者网络后重试，数据可能不一致')
                        return
                    receive_data.method = MyProtocol.methods.get(receive_data.method)
                    if receive_data.method == 'message':
                        message_code = int.from_bytes(receive_data.data, byteorder='big')
                        print(f'message_code:{message_code}')
                        if message_code == 0:
                            print("服务器好像出现了什么问题")
                        else:
                            print('文件传输完毕')
                else:
                    print('未接收到服务器响应')
            else:
                print(f'{filename} 不存在')
            print('--------------------------')

    def cmd_download(self, *args):  # 定义一个从服务器下载文件函数
        cmd_split = args[0].split()
        if len(cmd_split) > 1:
            filename = cmd_split[1]

            # 创建 MyProtocol 实例
            protocol = MyProtocol(
                version=2,
                magic=0x1234,
                method='download',
                filename=filename,
                data=b''
            )
            # 编码并发送数据
            encoded_data = protocol.encode()
            print(f'发送：{protocol}')
            self.client.sendall(encoded_data)
            total_data = receive_full_data(self.client, MyProtocol.header_size)
            if total_data:
                print('-------收到服务端回复-------')
                receive_data = MyProtocol.decode(total_data)
                if receive_data == 0:
                    print('请检查协议设置或者网络后重试，数据可能不一致')
                    return
                receive_data.method = MyProtocol.methods.get(receive_data.method)
                if receive_data.method == 'message':
                    message_code = int.from_bytes(receive_data.data, byteorder='big')
                    print(f'message_code:{message_code}')
                    if message_code == 0:
                        print("指定文件不存在")
                else:
                    with open(filename, 'wb') as f:
                        f.write(receive_data.data)
                    print(f'File {filename} download successfully.')
            else:
                print('未接收到服务器响应')
            print('--------------------------')

    def cmd_show(self, *args):  # 定义一个从服务器下载文件函数
        # 创建 MyProtocol 实例
        protocol = MyProtocol(
            version=2,
            magic=0x1234,
            method='show',
            filename='',
            data=b''
        )
        #手动设置MD5，用于测试
        # md5_test = b'test123456'
        # protocol = MyProtocol(
        #     version=22,
        #     magic=0x1234,
        #     method='show',
        #     filename='',
        #     data=b'',
        #     md5_test=md5_test
        # )
        # 编码并发送数据
        encoded_data = protocol.encode()
        print(f'发送：{protocol}')
        self.client.sendall(encoded_data)
        total_data = receive_full_data(self.client, MyProtocol.header_size)
        if total_data:
            print('-------收到服务端回复-------')
            receive_data = MyProtocol.decode(total_data)
            receive_data.method = MyProtocol.methods.get(receive_data.method)
            if receive_data == 0:
                print('请检查协议设置或者网络后重试，数据可能不一致')
                return
            if receive_data.method == 'message':
                message_code = int.from_bytes(receive_data.data, byteorder='big')
                print(f'message_code:{message_code}')
                if message_code == 0:
                    print("请检查协议设置或者网络后重试，数据可能不一致，或者服务器出现故障")
            else:
                print(f'show file lists')
                file_list = receive_data.data.decode('utf-8').splitlines()
                for idx, filename in enumerate(file_list, start=1):
                    print(f"{idx}. {filename}")
        else:
            print('未接收到服务器响应')
        print('--------------------------')


ftp = FtpClient()  # 实例化
ftp.connect('localhost', 9999)  # 连接服务器端口
ftp.interactive()  # 调用和服务器交互函数
